package com.example.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.filter.CharacterEncodingFilter;

import com.example.bean.UserDetailsServiceImpl;
import com.example.component.AjaxAccessDeniedHandler;
import com.example.component.AjaxAuthenticationEntryPointHandler;
import com.example.component.AjaxAuthenticationFailureHandler;
import com.example.component.AjaxAuthenticationSuccessHandler;
import com.example.component.AjaxLogoutSuccessHandler;
import com.example.component.SelfAuthenticationProvider;
import com.example.component.filter.CustomAuthenticationFilter;
import com.example.component.filter.JwtAuthenticationTokenFilter;

/*
 * Spring Security配置
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
    AjaxAuthenticationEntryPointHandler authenticationEntryPoint;  //  未登陆时返回 JSON 格式的数据给前端（否则为 html）
    @Autowired
    AjaxAuthenticationSuccessHandler authenticationSuccessHandler;  // 登录成功返回的 JSON 格式数据给前端（否则为 html）
    @Autowired
    AjaxAuthenticationFailureHandler authenticationFailureHandler;  //  登录失败返回的 JSON 格式数据给前端（否则为 html）
    @Autowired
    AjaxLogoutSuccessHandler  logoutSuccessHandler;  // 注销成功返回的 JSON 格式数据给前端（否则为 登录时的 html）
    @Autowired
    AjaxAccessDeniedHandler accessDeniedHandler;    // 无权访问返回的 JSON 格式数据给前端（否则为 403 html 页面）
    @Autowired
    SelfAuthenticationProvider provider; // 自定义安全认证
    @Autowired
    JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; // JWT 拦截器
	
	@Bean
    UserDetailsService customUserService() {
        return new UserDetailsServiceImpl();
    }
	
    @Override
    protected void configure(AuthenticationManagerBuilder perminssion) throws Exception {
    	perminssion.authenticationProvider(provider);
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	//添加转码
    	CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();  
    	encodingFilter.setEncoding("UTF-8");  
		encodingFilter.setForceEncoding(true);
		http.addFilterBefore(encodingFilter, CsrfFilter.class);
		
        http
        .cors()
        	.and()
    	.csrf()
    		.disable()

        .authorizeRequests()
        	.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()//处理跨域请求中的Preflight请求
        	.antMatchers("/login").permitAll()//对登录接口放行
//    		.antMatchers("/**").permitAll()//对测试接口放行
        	.anyRequest()
        	.access("@rbacauthorityservice.hasPermission(request,authentication)")//RBAC动态权限配置
        	.and()
        	
        .formLogin()  //开启登录
        	.and()
        	
        .logout()
        	.logoutSuccessHandler(logoutSuccessHandler)
        	.permitAll();
    	
    	
    	http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // 无权访问 JSON 格式的数据
    	http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);  // 插入自定义用户登录检查过滤器
    	http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // JWT Filter
    }
    
    //注册自定义的UsernamePasswordAuthenticationFilter
    @Bean
    CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
        CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
        
        filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);//登陆成功
        filter.setAuthenticationFailureHandler(authenticationFailureHandler);//登陆失败
        filter.setFilterProcessesUrl("/login");//登录接口URL

        //这句很关键，重用WebSecurityConfigurerAdapter配置的AuthenticationManager，不然要自己组装AuthenticationManager
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }
    
    @Override
    @Bean // share AuthenticationManager for web and oauth
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
